#ifndef ___fat32_subtransaccion19_escribir_datos_en_archivo

#define ___fat32_subtransaccion19_escribir_datos_en_archivo 1

#include "f32_mto.c"

#include "f32_opAL.c"
#include "f32_opAT.c"

struct fat32st19_datos {
  unsigned long clusterInicial;
  unsigned long posicionInicial;
  unsigned long cantidadDatos;
  char * datos;
  unsigned long * cadena;
  unsigned int conexion;
  fat32_lista_bloques_para_escribir * lbpe;
  unsigned long posicionActual;
};

unsigned char fat32st_escribir_datos_en_archivo(unsigned char, unsigned int, unsigned long, unsigned long, unsigned long, void *, void **,
                                                                                                                    unsigned char, void *);

unsigned char fat32st_escribir_datos_en_archivo (unsigned char estado, unsigned int transaccion, unsigned long clusterInicial,
                                                 unsigned long posicionInicial, unsigned long cantidadDatos, void * datosEscritura,
                                                 void ** datos, unsigned char estadoOp, void * datosOp) {
  struct fat32st19_datos * datosST = *datos;
  switch (estado) {
  case 0:
    datosST -> clusterInicial = clusterInicial;
    datosST -> posicionInicial = posicionInicial;
    datosST -> cantidadDatos = cantidadDatos;
    datosST -> datos = malloc(datosST -> cantidadDatos);
    memcpy(datosST -> datos, datosEscritura, datosST -> cantidadDatos);
    datosST -> conexion = fat32_obtener_conexion_para_transaccion(transaccion);
    datosST -> lbpe = malloc(sizeof(fat32_lista_bloques_para_escribir));
    fat32_operar_sobre_lista_bloques_para_escribir(FAT32_LBPE_CREAR, &(datosST -> lbpe), 0, 0, 0, NULL);
    fat32_crear_operacion(transaccion, &fat32op_obtener_cadena_clusteres, &(datosST -> clusterInicial), sizeof (datosST -> clusterInicial));
    return 1;
  case 1:
    datosST -> cadena = datosOp;
    fat32_quitar_operacion(transaccion);
    unsigned long cca;
    for (cca = 0; (datosST -> cadena)[cca]; cca ++);
    fat32_crear_operacion(transaccion, &fat32op_obtener_cadena_sectores_desde_clusteres, &(datosST -> cadena),
                                                                        (cca + 1) * sizeof(unsigned long int));
    return 2;
  case 2:
    free(datosST -> cadena);
    datosST -> cadena = datosOp;
    fat32_quitar_operacion(transaccion);
    datosST -> posicionActual = 0;
    return 3;
  case 3:
    if ((datosST -> posicionActual) >= (datosST -> cantidadDatos)) return 4;
    unsigned long dirSigSector = (datosST -> posicionInicial) + (datosST -> posicionActual);
    dirSigSector /= 512;
    unsigned long sectorActual = (datosST -> cadena)[dirSigSector];
    dirSigSector = (dirSigSector + 1) * 512;
    unsigned long cantidadActual;
    if (dirSigSector >= ((datosST -> posicionInicial) + (datosST -> cantidadDatos)))
      cantidadActual = (datosST -> cantidadDatos) - (datosST -> posicionActual);
    else
      cantidadActual = 512 - (((datosST -> posicionInicial) + (datosST -> posicionActual)) % 512);
    unsigned long offsetBloque = 512 * (sectorActual & 3) + (((datosST -> posicionInicial) + (datosST -> posicionActual)) % 512);
    unsigned long bloqueEscrituraActual = ((datosST -> cadena)[sectorActual]) & ~3L;
    fat32_operar_sobre_lista_bloques_para_escribir(FAT32_LBPE_ESCRIBIR, &(datosST -> lbpe), bloqueEscrituraActual, offsetBloque,
                                                               cantidadActual, (datosST -> datos) + (datosST -> posicionActual));
    datosST -> posicionActual += cantidadActual;
    return 3;
  case 4:
    free(datosST -> cadena);
    free(datosST -> datos);
    *datos = datosST -> lbpe;
    free(datosST);
    return 0;
  }
}

#endif